import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dart 特性演示',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _output = "";
  final ScrollController _scrollController = ScrollController();

  void _runAllFeatures() async {
    setState(() {
      _output = "";
    });
    _capturePrint(printHelloWorld);
    _capturePrint(variableExamples);
    _capturePrint(processControlExamples);
    _capturePrint(functionExamples);

    var voyager = Spacecraft('Voyager I', DateTime(1977, 9, 5));
    _capturePrint(() => voyager.describe());

    var voyager3 = Spacecraft.unlaunched('Voyager III');
    _capturePrint(() => voyager3.describe());

    var orbiter = Orbiter('Hubble', DateTime(1990, 4, 24), 547.0);
    setState(() {
      _output += '\n轨道器名称: ${orbiter.name}，高度: ${orbiter.altitude} km\n';
    });
    _scrollToBottom();

    var pilotedCraft = PilotedCraft('ISS', DateTime(2023, 1, 1));
    pilotedCraft.astronauts = 6;
    _capturePrint(() => pilotedCraft.describeCrew());

    var mockSpaceship = MockSpaceship('模拟航天器', DateTime(2023, 1, 1));
    _capturePrint(() => mockSpaceship.describe());

    await _capturePrintAsync(printWithDelay, '\n--- 延迟1秒 ---');
    var spacecraft = Spacecraft('旅行者号', null);
    var targets = ['火星', '木星'];
    await for (var msg in report(spacecraft, targets)) {
      setState(() {
        _output += '$msg\n';
      });
      _scrollToBottom();
      await Future.delayed(const Duration(seconds: 1));
    }

    _capturePrint(exceptionHandling);
  }

  void _capturePrint(VoidCallback func) {
    runZonedGuarded(
      () {
        func();
      },
      (error, stackTrace) {
        // 错误处理
        setState(() {
          _output += 'Error: $error\n';
        });
      },
      zoneSpecification: ZoneSpecification(
        print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
          setState(() {
            _output += '$line\n';
          });
          _scrollToBottom();
          parent.print(zone, line);
        },
      ),
    );
  }

  Future<void> _capturePrintAsync(
    Future<void> Function(String) func,
    String message,
  ) async {
    await runZonedGuarded(
      () async {
        await func(message);
      },
      (error, stackTrace) {
        setState(() {
          _output += 'Error: $error\n';
        });
      },
      zoneSpecification: ZoneSpecification(
        print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
          setState(() {
            _output += '$line\n';
          });
          _scrollToBottom();
          parent.print(zone, line);
        },
      ),
    );
  }

  void _scrollToBottom() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_scrollController.hasClients) {
        _scrollController.animateTo(
          _scrollController.position.maxScrollExtent,
          duration: const Duration(milliseconds: 300),
          curve: Curves.easeOut,
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Dart 特性演示')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            ElevatedButton(
              onPressed: _runAllFeatures,
              child: const Text('运行所有特性演示'),
            ),
            const SizedBox(height: 16),
            Expanded(
              child: SingleChildScrollView(
                controller: _scrollController,
                child: Container(
                  padding: const EdgeInsets.all(12),
                  decoration: BoxDecoration(
                    border: Border.all(color: Colors.grey.shade300),
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: SelectableText(
                    _output,
                    style: const TextStyle(fontFamily: 'Courier', fontSize: 14),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

void printHelloWorld() {
  print('Hello, World!');
}

void variableExamples() {
  var name = 'Voyager I';
  var year = 1977;
  var antennaDiameter = 3.7;
  var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
  var image = {
    'tags': ['saturn'],
    'url': '//path/to/saturn.jpg',
  };

  print('\n--- 变量示例 ---');
  print('name: $name');
  print('year: $year');
  print('antennaDiameter: $antennaDiameter');
  print('flybyObjects: $flybyObjects');
  print('image: $image');
}

void processControlExamples() {
  var year = 1977;
  var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];

  print('\n--- 流程控制示例 ---');

  if (year >= 2001) {
    print('21st century');
  } else if (year >= 1901) {
    print('20th century');
  }

  print('\nFlyby Objects:');
  for (final object in flybyObjects) {
    print(object);
  }

  print('\nMonths:');
  for (int month = 1; month <= 12; month++) {
    print(month);
  }

  while (year < 2016) {
    year += 1;
  }
  print('\n最终的 year: $year');
}

void functionExamples() {
  print('\n--- 函数示例 ---');

  int fibonacci(int n) {
    if (n == 0 || n == 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
  }

  var result = fibonacci(20);
  print('第 20 个斐波那契数: $result');

  var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
  flybyObjects.where((name) => name.contains('turn')).forEach(print);

  var add = (int a, int b) => a + b;
  print('两数相加: ${add(3, 5)}');
}

class Spacecraft {
  String name;
  DateTime? launchDate;

  int? get launchYear => launchDate?.year;

  Spacecraft(this.name, this.launchDate);
  Spacecraft.unlaunched(String name) : this(name, null);

  void describe() {
    print('\nSpacecraft: $name');
    var launchDate = this.launchDate;
    if (launchDate != null) {
      int years = DateTime.now().difference(launchDate).inDays ~/ 365;
      print('Launched: $launchYear ($years years ago)');
    } else {
      print('Unlaunched');
    }
  }
}

enum PlanetType { terrestrial, gas, ice }

enum Planet {
  mercury(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
  venus(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
  earth(planetType: PlanetType.terrestrial, moons: 1, hasRings: false),
  uranus(planetType: PlanetType.ice, moons: 27, hasRings: true),
  neptune(planetType: PlanetType.ice, moons: 14, hasRings: true);

  const Planet({
    required this.planetType,
    required this.moons,
    required this.hasRings,
  });

  final PlanetType planetType;
  final int moons;
  final bool hasRings;

  bool get isGiant =>
      planetType == PlanetType.gas || planetType == PlanetType.ice;
}

class Orbiter extends Spacecraft {
  double altitude;

  Orbiter(super.name, super.launchDate, this.altitude);
}

mixin Piloted {
  int astronauts = 1;
  void describeCrew() {
    print('Number of astronauts: $astronauts');
  }
}

class PilotedCraft extends Spacecraft with Piloted {
  PilotedCraft(String name, DateTime launchDate) : super(name, launchDate);
}

class MockSpaceship implements Spacecraft {
  @override
  String name;
  @override
  DateTime? launchDate;

  MockSpaceship(this.name, this.launchDate);

  @override
  int? get launchYear => launchDate?.year;

  @override
  void describe() {
    print('MockSpaceShip: $name');
    if (launchDate != null) {
      int years = DateTime.now().difference(launchDate!).inDays ~/ 365;
      print('Launched: ${launchDate!.year} ($years years ago)');
    } else {
      print('Unlaunched');
    }
  }
}

abstract class Describable {
  void describe();
  void describeWithEmphasis() {
    print('=========');
    describe();
    print('=========');
  }
}

Future<void> printWithDelay(String message) async {
  await Future.delayed(const Duration(seconds: 1));
  print(message);
}

Stream<String> report(Spacecraft craft, Iterable<String> objects) async* {
  for (final object in objects) {
    await Future.delayed(const Duration(seconds: 1));
    yield '${craft.name} flies by $object';
  }
}

void exceptionHandling() async {
  var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
  int astronauts = 1;

  if (astronauts == 0) {
    throw StateError('No astronauts.');
  }

  try {
    for (final object in flybyObjects) {
      var file = File('$object.txt');
      if (!await file.exists()) {
        await file.create();
        await file.writeAsString('Description of $object');
      }
      var description = await file.readAsString();
      print(description);
    }
  } on IOException catch (e) {
    print('Could not describe object: $e');
  } finally {
    flybyObjects.clear();
    print('Flyby objects cleared');
  }
}
